﻿using Grpc.Core;
using Microsoft.Extensions.Logging;
using Polly;
using QPZS;
using QPZS.ETK;
using System;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using Wicture.DbRESTFul;
using static QPZS.ETK.VinQueryRpc;

namespace Wicture.DTT.ETK.Protocol
{
    public static class VinQueryRpcService
    {
        private static object locker = new object();
        private static Channel channel;
        private static string channelAddress;

        public static void Init(string address)
        {
            channelAddress = address;
        }

        public static void Init()
        {
            Init(ConfigurationManager.Settings.Variables["BMW.VinQueryService"]);
        }

        private static Channel Channel
        {
            get
            {
                if (string.IsNullOrEmpty(channelAddress)) Init();

                if (channel == null || channel.State == ChannelState.Shutdown || channel.State == ChannelState.TransientFailure)
                {
                    try
                    {
                        lock (locker)
                        {
                            if (channel == null || channel.State == ChannelState.Shutdown || channel.State == ChannelState.TransientFailure)
                            {
                                channel?.ShutdownAsync().Wait();
                                channel = null;
                            }

                            if (channel == null)
                            {
                                LoggerManager.Logger.LogInformation($"初始化RPC通道: {channelAddress}。");
                                channel = new Channel(channelAddress, ChannelCredentials.Insecure);
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        channel?.ShutdownAsync().Wait();
                        channel = null;
                        LoggerManager.Logger.LogError(ex, $"通道创建失败: {channelAddress}。");
                        throw ex;
                    }
                }

                return channel;
            }
            set
            {
                lock (locker)
                {
                    channel = value;
                }
            }
        }

        public static async Task<VinResponse> Query(VinRequest request)
        {
            return await Call(async client => await client.QueryAsync(request));
        }

        public static async Task<AgentResponse> Agents(EmptyRequest request)
        {
            return await Call(async client => await client.AgentsAsync(request));
        }

        public static async Task<UpdateAgentResponse> UpdateAgent(UpdateAgentRequest request)
        {
            return await Call(async client => await client.UpdateAgentAsync(request));
        }

        private static async Task<T> Call<T>(Func<VinQueryRpcClient, Task<T>> func, [CallerMemberName]string methodName = "")
        {
            try
            {
                var reply = Policy.TimeoutAsync(30)
                .ExecuteAsync(() =>
                {
                    var client = new VinQueryRpcClient(Channel);
                    return func.Invoke(client);
                });

                return await reply;
            }
            catch (RpcException ex)
            {
                LoggerManager.Logger.LogError(ex, $"调用 VinQueryRpcClient.{methodName} 出错。");
                Channel = null;
                return default(T);
            }
        }
    }
}
